class MyPromise {
	// promise的三种状态
	static PENDING = "pending"
	static FULLFILLED = "fullfilled"
	static REJECT = "rejected"
	constructor(callback) {
		// 初始状态
		this.status = MyPromise.PENDING
		// 执行结果对应的状态
		this.executionStatus = null
		// 保存resolve函数
		this.resolveCallbacks = []
		// 保存reject函数
		this.rejectCallbacks = []

		//Promise的回调接收两个函数参数
		// callback(this.resolve, this.reject) //这样写会报错

		// constructor里面的this指向的是promise实例，而constructor外面指向的是其构造函数的原型对象
		// callback(this.resolve.bind(this), this.reject.bind(this))

		// 在原生promise中，如果promise自己报错，then的第二个函数能接收到，因此我们要用try…catch捕获
		try {
			callback(this.resolve.bind(this), this.reject.bind(this))
		} catch (error) {
			this.reject(error)
		}
	}
	// 实现resolve
	resolve(execResult) {
		// 初始状态为pending状态
		if (this.status == MyPromise.PENDING) {
			// 改变状态为fullfilled
			this.status = MyPromise.FULLFILLED
			// 改变promise执行结果的状态
			this.executionStatus = execResult
			// resolve在事件循环末尾执行
			this.resolveCallbacks.forEach(cb => cb(execResult))

		}
	}
	// 实现reject
	reject(execResult) {
		if (this.status === MyPromise.PENDING) {
			this.status = MyPromise.REJECT;
			this.executionStatus = execResult
			// reject在事件循环末尾执行
			this.rejectCallbacks.forEach(cb => cb(execResult))
		}
	}
	// 实现then()接收两个回调函数，一个是成功的回调，一个是失败的回调
	then(onResolve, onReject) {
		// 实现链式
		return new MyPromise((resolve, reject) => {
			// 在原生promise中，.then里的两个参数如果不为函数，也不会报错；但是我们的手写代码会报错，因此要加异步判断
			onResolve = typeof onResolve === 'function' ? onResolve : () => {}
			onReject = typeof onReject === 'function' ? onReject : () => {}

			// 如何实现异步呢？
			// if (this.status === MyPromise.FULLFILLED) {
			// 	onResolve(this.executionStatus)
			// }
			// if (this.status == MyPromise.REJECT) {
			// 	onReject(this.executionStatus)
			// }

			if (this.status == MyPromise.PENDING) { //实现异步
				this.resolveCallbacks.push(onResolve)
				this.rejectCallbacks.push(onReject)
			}

			// 要实现异步，先套上定时器
			if (this.status === MyPromise.FULLFILLED) {
				setTimeout(() => {
					onResolve(this.executionStatus)
				})
			}
			if (this.status == MyPromise.REJECT) {
				setTimeout(() => {
					onReject(this.executionStatus)
				})
			}
			// 问题又来了，promise.then是一个微任务，这又该如何实现
			// 实现方法：
			// 因为执行then之前没有执行resolve， 导致then当时的状态为PENDING待定状态， 所以我们加一步判断， 判断当前状态为待定时， 让then稍后再执行， 执行完了resolve再执行then

			// 具体的实现为， 创建this.resolveCallbacks = [] 保存resolve的执行结果
			// 创建this.rejectCallbacks = [] 保存reject的执行结果
			// 在then里， 判断当前状态为待定时， 将对应的函数onFULFILLED, onREJECT都push到对应数组中
			// 之后在resolve和reject里遍历数组
			// 这里还有一个坑， resolve和reject在事件循环末尾执行， 所以要在resolve和reject里加上setTimeout
		})
	}
	// 实现catch
	catch (onReject) {
		this.then(null, onReject)
	}
	// 实现finally
	finally() {

	}
	// 静态方法只能被构造函数调用
	// 实现race
	race(promisesArray = []) {
		return new MyPromise((resolve, reject) => {
			if (promiseAry.length === 0) {
				return;
			}
			// 遍历
			promisesArray.forEach((promise, index) => {
				if (promise instanceof MyPromise) {
					promise.then(res => {
						return resolve(res)
					}, err => {
						return reject(err)
					})
				} else {
					return resolve(promise)
				}
			})
		})
	}
	// 实现all
	all(promisesArray = []) {
		// 实现链式
		return new MyPromise((resolve, reject) => {
			// 工具函数
			const savePromises = []
			const saveResolvedPromises = (executorRes, executorIndex) => {
				savePromises[executorIndex] = executorRes
				if (savePromises.length === promisesArray.length) { //说明数组每一项的状态都是fullfilled
					return resolve(savePromises)
				}
			}
			// 遍历
			promisesArray.forEach((promise, index) => {
				//判断数组每一项是否为Promise对象
				if (promise instanceof MyPromise) {
					// 得到每一项的执行状态
					promise.then(res => {
						// 保存记录当前项是fullfilled状态，还需要测试剩余项，所以创建一个工具函数
						saveResolvedPromises(res, index)
					}, err => { //有一个状态为reject则为rejected
						return reject(err)
					})
				} else { //如果不是Promise对象,会先调用Promise.resolve()
					return saveResolvedPromises(resolve(promise), index)
				}
			})
		})
	}
	// 实现any
	any(promisesArray = []) {
		return new MyPromise((resolve, reject) => {
			let curRejectedCounts = 0;
			promisesArray.forEach((promise, index) => {
				if (promise instanceof MyPromise) {
					promise.then(res => { //只要有一个状态是fullfilled,则状态就是fullfilled
						return resolve(res)
					}, err => { //数组每项都返回rejected，才是rejected
						curRejectedCounts++
						if (curRejectedCounts == promisesArray.length) {
							reject(new AggregateError('all promises are rejected!!!'))
						}
					})
				} else {
					return resolve(promise)
				}
			})
		})
	}
	// 实现allSettled
	allSettled(promisesArray = []) {
		// 实现链式
		return new MyPromise((resolve, reject) => {
			let savePromises = []
			const saveAllPromises = (executorStatus, executorRes, executorIndex) => {
				let anotherKey = null;
				anotherKey = executorStatus == MyPromise.FULLFILLED ? "value" : "reason"
				savePromises[executorIndex] = {
					status: executorStatus,
					[anotherKey]: executorRes
				}
				if (savePromises.length == promisesArray.length) {
					return resolve(savePromises)
				}
			}
			promisesArray.forEach((promise, index) => {
				if (promise instanceof MyPromise) {
					promise.then(res => {
						saveAllPromises(MyPromise.FULLFILLED, res, index)
					}, err => {
						saveAllPromises(MyPromise.REJECT, err, index)
					})
				} else {
					saveAllPromises(MyPromise.FULLFILLED, promise, index)
				}
			})
		})
	}
}

let promise1 = new MyPromise((resolve, reject) => {
	resolve('hello MyPromise')
})
promise1.then(res => {
	console.log('promise1 sucess');
}, err => {
	console.log('promise1 error');
})

let promise2 = new MyPromise((resolve, reject) => {
	throw new Error('sorry MyPromise')
})
promise2.then(res => {
	console.log('promise2 sucess');
}, err => {
	console.log('promise2 error');
	// console.log(err.message);
})

let promise3 = new MyPromise((resolve, reject) => {
	resolve('hello')
	reject('sorry')
})
promise3.then(res => {
	console.log('promise3 sucess');
}, err => {
	// console.log(err.message);
	console.log('promise3 error');
})

//整理：
let promise = new Promise((resolve, reject) => {
	console.log('2')
	setTimeout(() => {
		resolve('5')
		console.log('4')
	})
})
promise.then(
	result => {
		console.log(result)
	}
)
/*
 **new一个实例输出2，运行遇到setTimeout异步先不执行，到then方法
 **then里面发现现在的状态是待定，就把函数参数push到对应数组
 **现在开始执行setTimeout里面的内容，先执行resolve
 **发现resolve函数上来就是一个setTimeout异步，只能出来先执行console.log('4')，输出4
 **最后执行在消息队列中的resolve函数
 */


// 实现链式: 把then中的功能返回一个新的promise就可以了
